package com.joyrec.util.db.redis

import com.top10.redis.Redis
import com.top10.redis.SingleRedis
import redis.clients.jedis.Jedis
import ws.very.util.lang.Implicits2
import redis.clients.jedis.JedisCommands
import redis.clients.jedis.SortingParams
import redis.clients.jedis.Client
import scala.collection.convert.WrapAsJava
//FIXME:冗余重构 过多函数生成
trait RedisTpl extends Redis {

  def hgetallOption(key: S) = {
    val data = hgetAll(key)
    if (data) Some(data)
    else None
  }

  def zrevrangePage(key: String, page: Int)(implicit pageCount: Int) =
    (zrevrange _).tupled(pageRangeInt(key, page))

  def zrevrangePageWithScore(key: String, page: Int)(implicit pageCount: Int) =
    (zrevrangeWithScores _).tupled(pageRangeInt(key, page))

  def allRangeInt(key: S) = (key, 0, -1)
  def allRangeLong(key: S) = (key, 0L, -1L)
  def pageRangeInt(key: String, page: Int)(implicit pageCount: Int) = {
    val start = page * pageCount
    (key, start, start + pageCount - 1)
  }
  def pageRangeLong(key: String, page: Int)(implicit pageCount: Int) = {
    val (key2, start, limit) = pageRangeInt(key, page)(pageCount)
    (key2, start: L, limit: L)
  }

  def zrevrangeAll(key: S) =
    ((zrevrange _).tupled)(allRangeInt(key))

  def zrevrangeAllWithScore(key: S) =
    (zrevrangeWithScores _).tupled(allRangeInt(key))

  def lrangeAll(key: S) =
    ((lrange _).tupled)(allRangeLong(key))

  def lrangePage(key: String, page: Int)(implicit pageCount: Int) =
    (lrange _).tupled(pageRangeLong(key, page))

}

trait RedisTplHelper {
  implicit def option2Map(m: O[Map[S, A]]) = m.getOrElse(Map())
  implicit def mapping2Str(m: Map[S, A]) = m.mapValues(_.toString)
}
trait SingleRedisTpl extends SingleRedis with RedisTpl {
  def hincrByTx[Err, Right] = (hincrBy _ tupled) and {
    case ((key, field, inc), now) =>
      tx: (L => Err | Right) =>
        try {
          val result = tx(now)
          if (result.isLeft) hincrBy(key, field, 0 - inc)
          result
        } catch {
          case e =>
            hincrBy(key, field, 0 - inc)
            throw e
        }
  }
  def allKeys = keys("*")
  def flushDB = run { _.flushDB() }
  def keyStartWith(start: S) = keys(start + "*")
  
  /**
   * 注意精浮问题
   */
  def hincrByFloat(key: S, field: S, increment: D) =
    this.run(_.hincrByFloat(key, field, increment))

  def zrangeByScore(key: S, min: S, max: S) =
    this.run { _.zrangeByScore(key, min, max) }

  /**
   * 并行会有bug
   */
  def hincrByDecimal(key: S, field: S, increment: BigDecimal) = this.synchronized {
    hset(key, field, hget(key, field).map { v => BigDecimal(v) + increment }.getOrElse((increment)).toString)
  }
}

trait AutoSelectSingleRedis extends SingleRedisTpl {
  val select: Int
  override def run[T](task: (Jedis) => T): T =
    super.run { t =>
      t.select(select)
      task(t)
    }

}
trait LogTrait extends SingleRedisTpl {
  override def hincrByDecimal(key: S, field: S, increment: BigDecimal) =
    log("hincrByDecimal", key, field, increment)(super.hincrByDecimal(key, field, increment))

  override def hincrByFloat(key: S, field: S, increment: D) =
    log("hincrByFloat", key, field, increment)(super.hincrByFloat(key, field, increment))

  override def del(key: String) =
    log("del", key)(super.del(key))

  override def get(key: String) =
    log("get", key)(super.get(key))

  override def ttl(key: String) =
    log("ttl", key)(super.ttl(key))

  override def expire(key: String, ttl: Int) =
    log("expire", key, ttl)(super.expire(key, ttl))

  //  override def eval(script:String,keyCount:Int,args:String*)=
  //    log("eval",script,keyCount,args)(super.eval(script,keyCount,args))

  override def eval(script: String) =
    log("eval", script)(super.eval(script))

  //  override def evalsha(script:String,keyCount:Int,args:String*)=
  //    log("evalsha",script,keyCount,args)(super.evalsha(script,keyCount,args))

  override def evalsha(hash: String) =
    log("evalsha", hash)(super.evalsha(hash))

  override def set(key: String, value: String) =
    log("set", key, value)(super.set(key, value))

  override def setnx(key: String, value: String) =
    log("setnx", key, value)(super.setnx(key, value))

  override def exists(key: String) =
    log("exists", key)(super.exists(key))

  override def mget(keys: Seq[String]) =
    log("mget", keys)(super.mget(keys))

  override def mset(keyvalues: Seq[(String, String)]) =
    log("mset", keyvalues)(super.mset(keyvalues))

  override def getset(key: String, field: String) =
    log("getset", key, field)(super.getset(key, field))

  override def hget(key: String, field: String) =
    log("hget", key, field)(super.hget(key, field))

  override def hexists(key: String, field: String) =
    log("hexists", key, field)(super.hexists(key, field))

  override def hgetAll(key: String) =
    log("hgetAll", key)(super.hgetAll(key))

  override def hgetMany(keys: Seq[String]) =
    log("hgetMany", keys)(super.hgetMany(keys))

  override def hincrBy(key: String, field: String, increment: Long) =
    log("hincrBy", key, field, increment)(super.hincrBy(key, field, increment))

  override def hset(key: String, field: String, value: String) =
    log("hset", key, field, value)(super.hset(key, field, value))

  override def hdel(key: String, field: String) =
    log("hdel", key, field)(super.hdel(key, field))

  override def hmget(key: String, fields: Seq[String]) =
    log("hmget", key, fields)(super.hmget(key, fields))

  override def hmset(key: String, details: Map[String, String]) =
    log("hmset", key, details)(super.hmset(key, details))

  override def incrby(key: String, increment: Int) =
    log("incrby", key, increment)(super.incrby(key, increment))

  override def incr(key: String) =
    log("incr", key)(super.incr(key))

  override def keys(pattern: String) =
    log("keys", pattern)(super.keys(pattern))

  override def put(key: String, values: Map[String, String]) =
    log("put", key, values)(super.put(key, values))

  override def smembers(key: String) =
    log("smembers", key)(super.smembers(key))

  override def scard(key: String) =
    log("scard", key)(super.scard(key))

  override def sadd(key: String, value: String*) =
    log("sadd", key, value)(super.sadd(key, value:_*))

  override def srem(key: String, value: String) =
    log("srem", key, value)(super.srem(key, value))

  override def sismember(key: String, value: String) =
    log("sismember", key, value)(super.sismember(key, value))

  override def scriptLoad(script: String) =
    log("scriptLoad", script)(super.scriptLoad(script))

  override def lpop(key: String) =
    log("lpop", key)(super.lpop(key))

  override def brpop(timeout: Int, keys: Seq[String]) =
    log("brpop", timeout, keys)(super.brpop(timeout, keys))

  override def llength(key: String) =
    log("llength", key)(super.llength(key))

  override def lrange(key: String, start: Long, end: Long) =
    log("lrange", key, start, end)(super.lrange(key, start, end))

  override def ltrim(key: String, start: Long, end: Long) =
    log("ltrim", key, start, end)(super.ltrim(key, start, end))

  override def lset(key: String, index: Long, value: String) =
    log("lset", key, index, value)(super.lset(key, index, value))

  override def lrem(key: String, value: String, number: Long) =
    log("lrem", key, value, number)(super.lrem(key, value, number))

  override def rpush(key: String, value: String) =
    log("rpush", key, value)(super.rpush(key, value))

  override def lpush(key: String, value: String) =
    log("lpush", key, value)(super.lpush(key, value))

  override def zadd(key: String, score: Double, value: String) =
    log("zadd", key, score, value)(super.zadd(key, score, value))

  override def zrem(key: String, member: String) =
    log("zrem", key, member)(super.zrem(key, member))

  override def zrevrange(key: String, start: Int, end: Int) =
    log("zrevrange", key, start, end)(super.zrevrange(key, start, end))

  override def zrevrangeWithScores(key: String, start: Int, end: Int) =
    log("zrevrangeWithScores", key, start, end)(super.zrevrangeWithScores(key, start, end))

  override def zrange(key: String, start: Int, end: Int) =
    log("zrange", key, start, end)(super.zrange(key, start, end))

  override def zrangeWithScores(key: String, start: Int, end: Int) =
    log("zrangeWithScores", key, start, end)(super.zrangeWithScores(key, start, end))

  override def zrank(key: String, member: String) =
    log("zrank", key, member)(super.zrank(key, member))

  override def zremrangeByScore(key: String, start: Double, end: Double) =
    log("zremrangeByScore", key, start, end)(super.zremrangeByScore(key, start, end))

  override def zremrangeByRank(key: String, start: Int, end: Int) =
    log("zremrangeByRank", key, start, end)(super.zremrangeByRank(key, start, end))

  override def zrevrank(key: String, member: String) =
    log("zrevrank", key, member)(super.zrevrank(key, member))

  override def zcard(key: String) =
    log("zcard", key)(super.zcard(key))

  override def zscore(key: String, member: String) =
    log("zscore", key, member)(super.zscore(key, member))

  override def zincrBy(key: String, increment: Double, member: String) =
    log("zincrBy", key, increment, member)(super.zincrBy(key, increment, member))

  override def zinterStore(key: String, strings: Seq[String]) =
    log("zinterStore", key, strings)(super.zinterStore(key, strings))

  override def zunionStore(key: String, strings: Seq[String]) =
    log("zunionStore", key, strings)(super.zunionStore(key, strings))
  def log[R](method: S, args: Any*)(result: => R): R

}

trait WithRedis {
  protected def redis: SingleRedisTpl
}

trait PutOverride extends Redis {
  override def put(key: String, values: Map[String, String]) = {
    if (values)
      syncAndReturn2 { t =>
        t.del(key) -> t.put(key, values)
      }
    else
      del(key)
    key
  }

}
